package com.xzakota.minesweeper.widget;

import com.xzakota.minesweeper.R;
import com.xzakota.minesweeper.controller.Game;
import com.xzakota.minesweeper.model.Observable;
import com.xzakota.minesweeper.model.Observer;
import com.xzakota.minesweeper.model.entity.CellBean;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import static com.xzakota.minesweeper.controller.GameResource.getIconResource;
import static com.xzakota.minesweeper.util.ImageUtils.changeIcon;
import static com.xzakota.minesweeper.util.ImageUtils.combineImageIcon;

/**
 * 格子组件
 * 
 * @author Xzakota
 */
public class CellLabel extends JLabel implements MouseListener, Observer {
    // 默认大小
    public static final int width = 28;
    public static final int height = 28;
    
    // 默认图标资源
    private static final Icon[] MINE_AMOUNT_ICONS = new Icon[9];
    private static ImageIcon ICON_MINE_UNKNOWN;
    private static ImageIcon ICON_MARK_SAFE;
    private static ImageIcon ICON_MARK_UNSAFE;
    private static ImageIcon ICON_MARK_MAYBE;
    private static ImageIcon ICON_MINE_MAYBE_SWEEP;
    private static ImageIcon ICON_MARK_MINE;
    private static ImageIcon ICON_MINE_EXPLODE;
    private static ImageIcon ICON_MARK_WRONG_MARK;
    
    // 鼠标状态
    private static long lastMousePressedTime = 0;
    private static boolean mouse1And3DoublePressed = false;
    private static boolean mouse1Pressed = false;
    private static boolean mouse3Pressed = false;
    
    // 格子实体模型
    public final CellBean model;

    public CellLabel(CellBean model) {
        this.model = model;
        this.model.addObserver(this);

        setPreferredSize(new Dimension(width, height));
        setBorder(BorderFactory.createEmptyBorder());
        setIcon(ICON_MINE_UNKNOWN);

        addMouseListener(this);
    }

    /**
     * 加载默认资源
     */
    public static void loadResource() {
        ICON_MINE_UNKNOWN = adaptiveIcon(getIconResource(R.Icon._GRID_INDEX_E));
        ICON_MARK_SAFE = adaptiveIcon(getIconResource(R.Icon.MARK_SAFE));
        ICON_MARK_UNSAFE = adaptiveIcon(combineImageIcon(ICON_MINE_UNKNOWN, adaptiveIcon(getIconResource(R.Icon.MARK_UNSAFE)), 1));
        ICON_MARK_MAYBE = adaptiveIcon(combineImageIcon(ICON_MINE_UNKNOWN, adaptiveIcon(getIconResource(R.Icon.MARK_MAYBE)), 1));
        ICON_MINE_MAYBE_SWEEP = adaptiveIcon(combineImageIcon(ICON_MARK_SAFE, adaptiveIcon(getIconResource(R.Icon.MARK_MAYBE)), 1));

        ICON_MARK_MINE = adaptiveIcon(getIconResource(R.Icon.MARK_MINE));
        ICON_MINE_EXPLODE = adaptiveIcon(getIconResource(R.Icon.MARK_MINE_EXPLODE));
        ICON_MARK_WRONG_MARK = adaptiveIcon(getIconResource(R.Icon.MARK_WRONG_MARK));

        MINE_AMOUNT_ICONS[0] = ICON_MARK_SAFE;
        MINE_AMOUNT_ICONS[1] = combineMakeSureIcon(getIconResource(R.Icon.MINE_1));
        MINE_AMOUNT_ICONS[2] = combineMakeSureIcon(getIconResource(R.Icon.MINE_2));
        MINE_AMOUNT_ICONS[3] = combineMakeSureIcon(getIconResource(R.Icon.MINE_3));
        MINE_AMOUNT_ICONS[4] = combineMakeSureIcon(getIconResource(R.Icon.MINE_4));
        MINE_AMOUNT_ICONS[5] = combineMakeSureIcon(getIconResource(R.Icon.MINE_5));
        MINE_AMOUNT_ICONS[6] = combineMakeSureIcon(getIconResource(R.Icon.MINE_6));
        MINE_AMOUNT_ICONS[7] = combineMakeSureIcon(getIconResource(R.Icon.MINE_7));
        MINE_AMOUNT_ICONS[8] = combineMakeSureIcon(getIconResource(R.Icon.MINE_8));
    }

    private static ImageIcon adaptiveIcon(ImageIcon icon) {
        return changeIcon(icon, width, height);
    }

    private static ImageIcon combineMakeSureIcon(ImageIcon icon) {
        return combineImageIcon(ICON_MARK_SAFE, icon, 0.15);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof CellBean cell) {
            switch (cell.status) {
                case CellBean.STATUS_UN_SWEEP:
                    switch (cell.mark) {
                        case CellBean.MARK_NO:
                            setIcon(ICON_MINE_UNKNOWN);
                            break;
                        case CellBean.MARK_MAYBE:
                            setIcon(ICON_MARK_MAYBE);
                            break;
                        case CellBean.MARK_SURE:
                            setIcon(ICON_MARK_UNSAFE);
                            break;
                        case CellBean.MARK_IS_A_MINE:
                            setIcon(ICON_MARK_MINE);
                            break;
                        case CellBean.MARK_WRONG_MARK:
                            setIcon(ICON_MARK_WRONG_MARK);
                            break;
                    }
                    break;
                case CellBean.STATUS_WILL_SWEEP:
                    if (cell.mark == CellBean.MARK_MAYBE) {
                        setIcon(ICON_MINE_MAYBE_SWEEP);
                    } else if (cell.mark == CellBean.MARK_NO) {
                        setIcon(ICON_MARK_SAFE);
                    }
                    break;
                case CellBean.STATUS_SWEPT:
                    if (cell.hasMine) {
                        setIcon(ICON_MINE_EXPLODE);
                    } else {
                        setIcon(MINE_AMOUNT_ICONS[cell.roundMineAmount]);
                    }
                    break;
            }
            if (cell.froze) {
                removeMouseListener(this);
            }
        }
    }

    @Override
    public void setIcon(Icon icon) {
        if (getIcon() != icon && icon instanceof ImageIcon) {
            super.setIcon(icon);
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
        if (e.getButton() == MouseEvent.BUTTON1) {
            if (mouse3Pressed) {
                if (System.currentTimeMillis() - lastMousePressedTime < 500) {
                    mouse1And3DoublePressed = true;
                    mouse1Pressed = false;
                    mouse3Pressed = false;
                    Game.dispatchEvent("willSweepRoundCell", model);
                }
            } else {
                mouse1Pressed = true;
                Game.dispatchEvent("willSweepACell", model);
            }
        } else if (e.getButton() == MouseEvent.BUTTON3) {
            if (mouse1Pressed) {
                if (System.currentTimeMillis() - lastMousePressedTime < 500) {
                    mouse1And3DoublePressed = true;
                    mouse1Pressed = false;
                    mouse3Pressed = false;
                    Game.dispatchEvent("willSweepRoundCell", model);
                }
            } else {
                mouse3Pressed = true;
            }
        }
        lastMousePressedTime = System.currentTimeMillis();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        if (mouse1And3DoublePressed) {
            Game.dispatchEvent("sweepRoundCell");
            mouse1And3DoublePressed = false;
        } else {
            if (mouse1Pressed && e.getButton() == MouseEvent.BUTTON1) {
                Game.dispatchEvent("sweepACell");
                mouse1Pressed = false;
            } else if (mouse3Pressed && e.getButton() == MouseEvent.BUTTON3) {
                Game.dispatchEvent("markACell", model);
                mouse3Pressed = false;
            }
        }

    }

    @Override
    public void mouseEntered(MouseEvent e) {
        if (mouse1And3DoublePressed) {
            Game.dispatchEvent("willSweepRoundCell", model);
        } else {
            if (mouse1Pressed) {
                Game.dispatchEvent("willSweepACell", model);
            }
        }

    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

}
